package com.gopay.common.util.concurrent;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 异步处理任务超时
 * @author ddh02
 * @TimeoutFuture
 * @2017/10/31 15:07  www.gopay.com.cn Inc.All rights reserved.
 */
public class TimeoutFuture<V> {

    /**任务开始时间标记 **/
    private long start;

    /**定义超时时间 毫秒**/
    private int timeout = 6000;

    /**要处理的 future **/
    private Future delegateRef;

    /**定时器**/
    private Future<?> timer;

    /***
     * 回调监听器
     */
    private TimeoutFutureListener<V> listener;


    /**
     * 监听接口
     * @param <V>
     */
    public interface TimeoutFutureListener<V> {
        /**完成**/
        void success(V v);
        /**取消**/
        void cancel();
        /**异常**/
        void error(Exception e);
    }

    /***
     * 设置异步校验
     * @param delegate 委托的future
     * @param delay    首次延时时间
     * @param time      每次循环时间
     * @param timeUnit
     * @param scheduledExecutor  定时执行器
     */
    public void withTimeout(Future delegate, long delay, long time, TimeUnit timeUnit, ScheduledExecutorService scheduledExecutor) {
        this.delegateRef = delegate;

        TimeoutFuture.Fire<V> fire = new TimeoutFuture.Fire<V>(this);
        this.timer = scheduledExecutor.scheduleWithFixedDelay(fire, delay, time, timeUnit);
    }

    /**
     * 内部定时触发方法
     * @param <V>
     */
    private static final class Fire<V> implements Runnable {

        private static Logger logger = LoggerFactory.getLogger(Fire.class);

        TimeoutFuture<V> timeoutFutureRef;

        Fire(TimeoutFuture<V> timeoutFuture) {
            this.timeoutFutureRef = timeoutFuture;
        }

        @Override
        public void run() {

            TimeoutFuture<V> timeoutFuture = timeoutFutureRef;
            //引用为空 不执行
            if (timeoutFuture == null) {
                logger.info("timeoutFuture is null");
                return;
            }
            Future<V> delegate = timeoutFuture.delegateRef;
            //如果future 返回是空  不执行
            if (delegate == null) {
                logger.info("delegate is null");
                return;
            }

            //如果任务未执行
            if (timeoutFuture.getStart() == 0) {
                logger.info("start time  is  null");
                return;
            }

           // timeoutFutureRef = null;
            //如果任务完成了
            if (delegate.isDone()) {

                //调用 回调函数
                if (timeoutFuture.getListener() != null) {
                    try {
                        timeoutFuture.getListener().success(delegate.get());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (ExecutionException e) {
                        e.printStackTrace();
                    }
                }

                //回收资源
                cleanRes(timeoutFuture);
            } else {
                //任务没有做完

                //判断是否  真的超时
                //因为虽然 任务执行了 但是定时器执行的时候  任务可能是刚开始执行 所以还需要判定 是否真的超时
                long timeDiff = System.currentTimeMillis() - timeoutFuture.getStart();
                if (timeDiff < timeoutFuture.timeout) {
                    logger.info("本次调度任务未超时 返回等待下次检测 diff={}, timeout={}", new Object[]{timeDiff, timeoutFuture.timeout});
                    return;
                }

                try {
                    //timeoutFuture.setException(new TimeoutException("Future timed out: " + delegate));
                    //这个该有些什么动作呢..
                    logger.error("取消任务" + Thread.currentThread().getName());
                    // 执行future 的 取消操作
                    delegate.cancel(true);

                    if (timeoutFuture.getListener() != null) {
                        timeoutFuture.getListener().cancel();
                    }
                } finally {
                    //回收资源
                    cleanRes(timeoutFuture);
                }
            }
        }

        private void cleanRes(TimeoutFuture<V> timeoutFuture) {
            //取消timer 定时器任务
            timeoutFuture.timer.cancel(false);
            //回收定时任务
            timeoutFuture.timer = null;
            //回收future
            timeoutFuture.delegateRef = null;
            //回收该类对象
            timeoutFuture = null;
        }
    }

    public TimeoutFuture() {

    }

    /**
     * 设置任务超时时间 默认6000  毫秒
     * @param timeout
     */
    public TimeoutFuture(int timeout) {
        if (timeout <= 0) {
            throw new IllegalArgumentException("超时时间 不允许小于0");
        }
        this.timeout = timeout;
    }

    public long getStart() {
        return start;
    }

    public void setStart(long start) {
        this.start = start;
    }

    public Future getDelegateRef() {
        return delegateRef;
    }

    public void setDelegateRef(Future delegateRef) {
        this.delegateRef = delegateRef;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public Future<?> getTimer() {
        return timer;
    }

    public void setTimer(Future<?> timer) {
        this.timer = timer;
    }

    public TimeoutFutureListener<V> getListener() {
        return listener;
    }

    public void setListener(TimeoutFutureListener<V> listener) {
        this.listener = listener;
    }
}
